#include "frozen-bubble.h"

FBWidgetLayer *rootlayer = NULL;

FBWidget *widget_new (FBWidgetType type, int x, int y)
{
	FBWidget *widget;
	
	if (!(widget = malloc (sizeof (FBWidget))))
	{
		fprintf (logfile, "widget_new: Unable to malloc FBWidget\n");
		exit (EXIT_FAILURE);
		return NULL;
	}
	
	widget->type = type;
	widget->layer = NULL;
	widget->image = NULL;
	widget->image_active = NULL;
	widget->x = x;
	widget->y = y;
	widget->active = FALSE;
	widget->can_active = FALSE;
	
	widget->on_press = NULL;
	
	widget->anim_count = 0;
	widget->anim_index = 0;
	widget->anim_x = 0;
	widget->anim_y = 0;
	widget->anim_only_active = TRUE;
	
	widget->dirty = FALSE;
	widget->always_dirty = FALSE;
	
	widget->next = NULL;
	
	return widget;
}

FBWidget *widget_new_image (FBImage *img, int x, int y)
{
	FBWidget *widget = widget_new (Image, x, y);
	
	widget->image = img;
	
	return widget;
}

FBWidget *widget_new_button (FBImage *img, FBImage *active, int x, int y)
{
	FBWidget *widget = widget_new (Button, x, y);
	
	widget->image = img;
	widget->image_active = active;
	widget->can_active = TRUE;
	
	return widget;
}

FBWidgetLayer *widget_layer_new (FBWidgetLayer *prev)
{
	FBWidgetLayer *layer;
	
	if (!(layer = malloc (sizeof (FBWidgetLayer))))
	{
		fprintf (logfile, "widget_new: Unable to malloc FBWidgetLayer\n");
		exit (EXIT_FAILURE);
		return NULL;
	}
	
	layer->x = 0;
	layer->y = 0;
	layer->bg = NULL;
	layer->widgets = NULL;
	layer->prev = prev;
	layer->next = NULL;
	
	layer->on_postrender = NULL;
	
	if (prev)
		prev->next = layer;
	
	return layer;
}

FBWidget *widget_layer_adopt (FBWidgetLayer *layer, FBWidget *widget)
{
	widget->layer = layer;
	
	// Need to render the widget at least once
	widget->dirty = TRUE;
	
	return widget;
}

void widget_layer_append (FBWidgetLayer *layer, FBWidget *widget)
{
	widget = widget_layer_adopt (layer, widget);
	
	if (!layer->widgets)
	{
		layer->widgets = widget;
		
		if (widget->can_active)
			widget->active = TRUE;
		
		return;
	}
	
	FBWidget *last = layer->widgets;
	bool any_active = last->active;
	
	while (last->next)
	{
		last = last->next;
		any_active |= last->active;
	}
	
	last->next = widget;
	
	if (!any_active && widget->can_active)
		widget->active = TRUE;
}

void _widget_free_all (FBWidget *widget)
{
	if (widget->next)
		_widget_free_all (widget->next);
	
	free (widget);
}

void widget_layer_free (FBWidgetLayer *layer)
{
	if (layer->widgets)
		_widget_free_all (layer->widgets);
	
	if (layer->prev)
	{
		layer->prev->next = NULL;
		widget_layer_alldirty (layer->prev);
	}
	
	free (layer);
}

void widget_render (FBWidget *widget)
{
	FBImage *bg_img;
	bool should_render = widget->dirty || widget->always_dirty;
	SDL_Rect widget_rect;
	
	if (widget->active)
		bg_img = widget->image_active;
	else
		bg_img = widget->image;
	
	if (should_render)
	{
		widget_rect.x = widget->layer->x + widget->x;
		widget_rect.y = widget->layer->y + widget->y;
		widget_rect.w = bg_img->surface->w;
		widget_rect.h = bg_img->surface->h;
		
		if (widget != widget->layer->bg)
			SDL_BlitSurface (widget->layer->bg->image->surface, &widget_rect, screen, &widget_rect);
		
		SDL_BlitSurface (bg_img->surface, &bg_img->rect, screen, &widget_rect);
		
		widget->dirty = FALSE;
	}
	
	if (widget->anim_count > 0)
	{
		FBImage *anim_img;
		int anim_prev_index = widget->anim_index;
		SDL_Rect anim_rect, anim_bg_rect;
		
		if (!widget->layer->next && (widget->active || !widget->anim_only_active))
		{
			anim_img = widget->anim[widget->anim_index++];
			
			if (widget->anim_index >= widget->anim_count)
				widget->anim_index = 0;
		}
		else
			anim_img = widget->anim[0];
		
		if (should_render || (widget->anim_index != anim_prev_index))
		{
			anim_rect.x = widget->layer->x + widget->x + widget->anim_x;
			anim_rect.y = widget->layer->y + widget->y + widget->anim_y;
			anim_rect.w = anim_img->surface->w;
			anim_rect.h = anim_img->surface->h;
			
			if (!should_render && (widget != widget->layer->bg))
			{
				// If the widget wasn't rendered as a whole this time, the
				// area behind the animation still needs to be rendered
				
				SDL_BlitSurface (widget->layer->bg->image->surface, &anim_rect, screen, &anim_rect);
				
				anim_bg_rect.x = bg_img->rect.x + widget->anim_x;
				anim_bg_rect.y = bg_img->rect.y + widget->anim_y;
				anim_bg_rect.w = anim_img->surface->w;
				anim_bg_rect.h = anim_img->surface->h;
				
				SDL_BlitSurface (bg_img->surface, &anim_bg_rect, screen, &anim_rect);
			}
			
			SDL_BlitSurface (anim_img->surface, &anim_img->rect, screen, &anim_rect);
		}
	}
}

void widget_layer_render (FBWidgetLayer *layer)
{
	widget_render (layer->bg);
	
	FBWidget *widget = layer->widgets;
	while (widget)
	{
		widget_render (widget);
		widget = widget->next;
	}
	
	if (layer->on_postrender)
		layer->on_postrender (layer);
	
	if (layer->next)
		widget_layer_render (layer->next);
}

void widget_layer_alldirty (FBWidgetLayer *layer)
{
	FBWidget *widget = layer->widgets;
	
	if (layer->bg)
		layer->bg->dirty = TRUE;
	
	while (widget)
	{
		widget->dirty = TRUE;
		widget = widget->next;
	}
}

void widget_layer_return (FBWidgetLayer *layer)
{
	while (layer->next)
		layer = layer->next;
	
	if (layer == rootlayer)
		return;
	
	widget_layer_free (layer);
}

void widget_layer_root (FBWidgetLayer *layer)
{
	if (rootlayer)
		widget_layer_free (rootlayer);
	
	rootlayer = layer;
}

void widget_activate (FBWidget *widget)
{
	widget->anim_index = 0;
	
	widget->active = TRUE;
	widget->dirty = TRUE;
}

void widget_deactivate (FBWidget *widget)
{
	widget->active = FALSE;
	widget->dirty = TRUE;
}

void widget_activate_prev (FBWidgetLayer *layer)
{
	while (layer->next)
		layer = layer->next;
	
	FBWidget *widget = layer->widgets;
	FBWidget *prev = NULL;
	
	while (widget && widget->next)
	{
		if (widget->can_active)
			prev = widget;
		
		widget = widget->next;
		
		if (widget->active)
		{
			if (prev)
			{
				widget_deactivate (widget);
				widget_activate (prev);
			}
			
			break;
		}
	}
}

void widget_activate_next (FBWidgetLayer *layer)
{
	while (layer->next)
		layer = layer->next;
	
	FBWidget *widget = layer->widgets;
	
	while (widget)
	{
		if (widget->active)
		{
			if (widget->next)
			{
				FBWidget *next = widget->next;
				
				while ((!next->can_active) && next->next)
					next = next->next;
				
				if (next)
				{
					widget_deactivate (widget);
					widget_activate (next);
				}
			}
			
			break;
		}
		
		widget = widget->next;
	}
}

void widget_press_active (FBWidgetLayer *layer)
{
	while (layer->next)
		layer = layer->next;
	
	FBWidget *widget = layer->widgets;
	
	while (widget)
	{
		if (widget->active)
		{
			if (widget->on_press)
				widget->on_press (widget);
			
			break;
		}
		
		widget = widget->next;
	}
}

